#include "acl_stdafx.hpp"
#include "acl_cpp/stdlib/pipe_stream.hpp"
#include "acl_cpp/stdlib/string.hpp"

namespace acl {

	pipe_string::pipe_string()
	{
		m_pBuf = NEW string(128);
		m_pSavedBufPtr = m_pBuf;
		m_pos = 0;
	}

	pipe_string::pipe_string(string& s)
	{
		m_pBuf = &s;
		m_pSavedBufPtr = NULL;
		m_pos = 0;
	}

	pipe_string::~pipe_string()
	{
		if (m_pSavedBufPtr)
			delete m_pSavedBufPtr;
	}

	int pipe_string::push_pop(const char* in, size_t len,
		string* out, size_t max /* = 0 */)
	{
		if (in && len > 0)
			m_pBuf->append(in, len);

		if (out == NULL)
			return (0);

		len = m_pBuf->length();
		acl_assert(len >= m_pos);
		len -= m_pos;

		if (len == 0)
			return (0);
		
		size_t n;
		if (max > 0)
			n = max > len ? len : max;
		else
			n = len;

		out->append(m_pBuf->c_str() + m_pos, n);
		m_pos += n;
		return (n);
	}

	int pipe_string::pop_end(string* out, size_t max /* = 0 */)
	{
		if (out == NULL)
			return (0);
		size_t n = m_pBuf->length();
		acl_assert(n >= m_pos);
		n -= m_pos;
		if (n == 0)
			return (0);
		if (max > 0 && n > max)
			n = max;
		out->append(m_pBuf->c_str() + m_pos, n);
		m_pos += n;
		return (n);
	}

	////////////////////////////////////////////////////////////////////////

	pipe_manager::pipe_manager()
	{
		m_pBuf1 = NEW string(128);
		m_pBuf2 = NEW string(128);
		m_pPipeStream = NULL;
	}

	pipe_manager::~pipe_manager()
	{
		delete m_pBuf1;
		delete m_pBuf2;
		if (m_pPipeStream)
			delete m_pPipeStream;
	}

	bool pipe_manager::push_back(pipe_stream* stream)
	{
		std::list<pipe_stream*>::const_iterator cit = m_streams.begin();

		for (; cit != m_streams.end(); ++cit)
		{
			if (stream == *cit)
				return (false);
		}

		m_streams.push_back(stream);
		return (true);
	}

	bool pipe_manager::push_front(pipe_stream* stream)
	{
		std::list<pipe_stream*>::const_iterator cit = m_streams.begin();

		for (; cit != m_streams.end(); ++cit)
		{
			if (stream == *cit)
				return (false);
		}

		m_streams.push_front(stream);
		return (true);
	}

	bool pipe_manager::update(const char* src, size_t len, pipe_stream* out /* = NULL */)
	{
		std::list<pipe_stream*>::iterator it = m_streams.begin();

		string* pBuf = m_pBuf1;
		string* pLast = pBuf;
		pBuf->clear();

		for (; it != m_streams.end(); ++it)
		{
			if (len > 0 && (*it)->push_pop(src, len, pBuf) == -1)
				return (false);
			src = pBuf->c_str();
			len = pBuf->length();
			pLast = pBuf;
			if (pBuf == m_pBuf1)
				pBuf = m_pBuf2;
			else
				pBuf = m_pBuf1;
			pBuf->clear();
		}

		if (!pLast->empty() && out != NULL)
			return (out->push_pop(pLast->c_str(), pLast->length(), NULL) == -1 ? false : true);
		return (true);
	}

	bool pipe_manager::update_end(pipe_stream* out /* = NULL */)
	{
		if (m_streams.empty())
			return (true);

		std::list<pipe_stream*>::iterator it = m_streams.begin();

		string* pBuf = m_pBuf2;
		pBuf->clear();

		if ((*it)->pop_end(pBuf) == -1)
			return (false);

		string* pLast = pBuf;
		const char* ptr = pLast->c_str();
		size_t len = pLast->length();

		pBuf = m_pBuf1;
		pBuf->clear();

		++it;
		for (; it != m_streams.end(); ++it)
		{
			if (len > 0 && (*it)->push_pop(ptr, len, pBuf) == -1)
				return (false);
			if ((*it)->pop_end(pBuf) == -1)
				return (false);

			pLast = pBuf;
			ptr = pLast->c_str();
			len = pLast->length();

			if (pBuf == m_pBuf1)
				pBuf = m_pBuf2;
			else
				pBuf = m_pBuf1;
			pBuf->clear();
		}

		if (!pLast->empty() && out != NULL)
			return (out->push_pop(pLast->c_str(), pLast->length(), NULL) == -1 ? false : true);
		return (true);
	}

	pipe_manager& pipe_manager::operator<<(const acl::string& s)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update(s.c_str(), s.length(), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(const acl::string* s)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update(s->c_str(), s->length(), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(const char* s)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update(s, strlen(s), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(acl_int64 n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(acl_uint64 n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(long n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(unsigned long n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(int n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(unsigned int n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(short n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(unsigned short n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(char n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	pipe_manager& pipe_manager::operator<<(unsigned char n)
	{
		if (m_pPipeStream == NULL)
			m_pPipeStream = NEW pipe_string();
		update((const char*) &n, sizeof(n), m_pPipeStream);
		return (*this);
	}

	char* pipe_manager::c_str() const
	{
		if (m_pPipeStream)
			return (m_pPipeStream->c_str());
		else
		{
			static const char* dummy = "";
			return ((char*) dummy);
		}
	}

	size_t pipe_manager::length() const
	{
		if (m_pPipeStream)
			return (m_pPipeStream->length());
		else
			return (0);
	}

	void pipe_manager::clear()
	{
		if (m_pPipeStream)
			m_pPipeStream->clear();
	}

} // namespace acl
